import { Graph, Cell, Node, Edge } from '@antv/x6'
import { Clipboard } from '@antv/x6-plugin-clipboard'
import { Keyboard } from '@antv/x6-plugin-keyboard'
import { History } from '@antv/x6-plugin-history'
import { Selection } from '@antv/x6-plugin-selection'
import { Export } from '@antv/x6-plugin-export'
import dagre from 'dagre'
import { ElMessage } from "element-plus";
import { copy } from '@/utils/index'
import { useAppStore } from '@/stores/app'
const appStore = useAppStore()

export function initGraph() {
  // 画布
  const graph = new Graph({
    container: document.getElementById('container')!, // 画布的容器
    autoResize: true, // 是否监听容器大小改变，并自动更新画布大小
    panning: true, // 画布是否可以拖拽平移
    mousewheel: true, // 鼠标滚轮缩放
    interacting: { // 定制节点和边的交互行为
      nodeMovable: false, // 节点是否可以被移动
      edgeMovable: false // 边是否可以被移动
    },
  })
  // 复制粘贴
  graph.use(
    new Clipboard({
      enabled: true,
    }),
  )
  // 快捷键
  graph.use(
    new Keyboard({
      enabled: true,
    }),
  )
  // 撤销重做
  graph.use(
    new History({
      enabled: true,
      beforeAddCommand(event: string, args: any) {
        if (event === 'cell:change:*' && ['tools'].includes(args.key) ) {
          return false
        }
        return true
      }
    }),
  )
  // 框选
  graph.use(
    new Selection({
      enabled: true,
      multiple: false, // 是否启用点击多选
    }),
  )
  graph.use(new Export())


  // 新增子主题
  graph.bindKey('tab', () => {
    if (!graph.isSelectionEmpty()) {
      graph.batchUpdate(() => {
        const [cell] = graph.getSelectedCells()
        addCell(cell)
        layout(graph)
      })
    }
    return false
  })
  // 新增同级主题
  graph.bindKey('enter', () => {
    const [cell] = graph.getSelectedCells()
    if (!graph.isRootNode(cell)) {
      graph.batchUpdate(() => {
        const [edge] = graph.getIncomingEdges(cell) as Edge[]
        addCell(edge.getSourceCell() as Cell)
        layout(graph)
      })
    }
    return false
  })
  // 新增父主题
  graph.bindKey('shift+tab', () => {
    const [cell] = graph.getSelectedCells()
    if (!graph.isRootNode(cell)) {
      graph.batchUpdate(() => {
        const [edge] = graph.getIncomingEdges(cell) as Edge[]
        const node = addCell(edge.getSourceCell() as Cell, 66, 40, '父主题')
        edge.setSource(node)
        layout(graph)
      })
    }
    return false
  })
  // 选中节点的ID
  let selectCellId = ''
  // 复制
  graph.bindKey('command+c', () => {
    if (!graph.isSelectionEmpty()) {
      if (isCut) {
        const copyCell = graph.getCellById(selectCellId)
        removeCell(copyCell)
        isCut = false
      }
      const cells = graph.getSelectedCells()
      selectCellId = cells[0].id
      ElMessage.success('复制成功!')
    }
    return false
  })
  // 是否正在剪切
  let isCut = false
  // 剪切
  graph.bindKey('command+x', () => {
    if (!graph.isSelectionEmpty()) {
      graph.batchUpdate(() => {
        if (isCut) {
          const copyCell = graph.getCellById(selectCellId)
          removeCell(copyCell)
          isCut = false
        }
        const cells = graph.getSelectedCells()
        selectCellId = cells[0].id
        // 根节点不能删除
        if (!graph.isRootNode(cells[0])) {
          const [edge] = graph.getIncomingEdges(cells[0]) as Edge[]
          graph.removeCell(edge)
          hideCell(cells[0])
          layout(graph)
          isCut = true
        }
      })
    }
    return false
  })
  function hideCell(cell: Cell) {
    // 隐藏后续节点、边
    if (!graph.isLeafNode(cell)) {
      (graph.getSuccessors(cell)).forEach(node => {
        node.hide()
        const [edge] = graph.getIncomingEdges(node) as Edge[]
        edge.hide()
      })
    }
    cell.hide()
  }
  // 粘贴
  graph.bindKey('command+v', () => {
    if (!graph.isSelectionEmpty() && selectCellId) {
      graph.batchUpdate(() => {
        const copyCell = graph.getCellById(selectCellId)
        const text = copyCell.getAttrByPath('text/text') as string
        const [cell] = graph.getSelectedCells()
        const node = copyCell as Node
        const { width, height } = node.size()
        const newCell = addCell(cell, width, height, text)
        childNode(copyCell, newCell)
        if (isCut) {
          removeCell(copyCell)
          isCut = false
          selectCellId = newCell.id
        }
        layout(graph)
      })
    }
    return false
  })
  // 复制子节点
  function childNode(copyCell: Cell, newCell: Cell) {
    if (!graph.isLeafNode(copyCell)) {
      const edges = graph.getOutgoingEdges(copyCell)
      edges?.forEach(edge => {
        const copyNode = edge.getTargetCell() as Cell
        const text = copyNode.getAttrByPath('text/text') as string
        const node = copyNode as Node
        const { width, height } = node.size()
        const newNode = addCell(newCell, width, height, text)
        // 死循环
        if (copyCell.id !== selectCellId) {
          childNode(copyNode, newNode)
        }
      })
    }
  }
  // 删除
  graph.bindKey('del', () => {
    if (!graph.isSelectionEmpty()) {
      const [cell] = graph.getSelectedCells()
      if (!graph.isRootNode(cell)) {
        graph.batchUpdate(() => {
          const [cell] = graph.getSelectedCells()
          removeCell(cell)
          layout(graph)
        })
      }
    }
    return false
  })
  function removeCell(cell: Cell) {
    // 删除后续节点
    if (!graph.isLeafNode(cell)) {
      (graph.getSuccessors(cell)).forEach(node => {
        graph.removeCell(node)
      })
    }
    graph.removeCell(cell)
  }
  // 撤销
  graph.bindKey('command+z', () => {
    graph.undo()
    graph.centerContent()
    return false
  })
  // 重做
  graph.bindKey('command+y', () => {
    graph.redo()
    graph.centerContent()
    return false
  })
  // 节点上移
  graph.bindKey('command+up', () => {
    move('up')
  })
  // 节点下移
  graph.bindKey('command+down', () => {
    move('down')
  })
  // 有bug
  function move(type : 'up' | 'down') {
    if (!graph.isSelectionEmpty()) {
      const [cell] = graph.getSelectedCells()
      const parent = graph.getNeighbors(cell, { incoming: true })[0]
      const edges = graph.getOutgoingEdges(parent)
      const [edge] = graph.getIncomingEdges(cell) as Edge[]
      edges?.forEach((node, index) => {
        if (node.id === edge.id) {
          graph.batchUpdate(() => {
            const moveCell = moveEdge(index, edges, type)
            const targetNode = moveCell.getTargetNode() as Node
            edge.setTarget(targetNode)
            moveCell.setTarget(cell as Node)
            layout(graph)
          })
        }
      })
    }
    return false
  }
  function moveEdge(index: number, edges: Edge[], type : 'up' | 'down') {
    if (type === 'up') {
      return edges[index === 0 ? (edges.length - 1) : (index - 1)]
    } else {
      return edges[index === (edges.length - 1) ? 0 : (index + 1)]
    }
  }
  // 保存
  graph.bindKey('command+s', () => {
    copy(JSON.stringify(graph.toJSON()))
    return false
  })

  // 展开、收起
  function hideCells(cell: Cell) {
    if (!graph.isLeafNode(cell)) {
      graph.batchUpdate(() => {
        const nodes = graph.getSuccessors(cell)
        nodes.forEach(node => {
          node.isVisible() ? node.hide() : node.show()
          const [edge] = graph.getIncomingEdges(node) as Edge[]
          edge.isVisible() ? edge.hide() : edge.show()
        })
        if (nodes[0].isVisible()) {
          cell.removeTools()
        } else {
          addTools(cell, nodes.length)
        }
        layout(graph)
      })
    }
  }
  function addTools(node: Cell, length: number) {
    node.addTools({
      name: 'button',
      args: {
        markup: [
          {
            tagName: 'circle',
            selector: 'button',
            attrs: {
              r: 8,
              stroke: '#8f8f8f',
              strokeWidth: 1,
              fill: 'white',
              cursor: 'pointer',
            },
          },
          {
            tagName: 'text',
            textContent: length,
            selector: 'icon',
            attrs: {
              fill: '#8f8f8f',
              fontSize: 10,
              textAnchor: 'middle',
              pointerEvents: 'none',
              y: '0.3em',
            },
          },
        ],
        x: '100%',
        y: '50%',
        offset: { x: 9, y: 0 },
        onClick() {
          hideCells(node)
        },
      },
    })
  }
  graph.on('edge:mouseenter', ({ edge }) => {
    edge.addTools({
      name: 'button',
      args: {
        markup: [
          {
            tagName: 'circle',
            selector: 'button',
            attrs: {
              r: 5,
              stroke: '#8f8f8f',
              strokeWidth: 2,
              fill: 'white',
              cursor: 'pointer',
            },
          },
        ],
        x: '100%',
        y: '50%',
        offset: { x: 9.5, y: 0 },
        onClick() {
          hideCells(edge.getSourceCell()!)
        },
      },
    })
  })
  graph.on('edge:mouseleave', ({ edge }) => {
    edge.removeTools()
  })

  // 新增节点
  function addNode(width: number, height: number, label: string) {
    return graph.addNode({
      x: 200,
      y: 200,
      width,
      height,
      label,
      attrs: {
        body: {
          strokeWidth: 1,
          stroke: '#8f8f8f',
          fill: '#fff',
          rx: 6,
          ry: 6,
        },
        text: {
          refX: 12,
          refY: '50%',
          textAnchor: 'start',
        },
      },
    })
  }
  function addCell(cell: Cell, width: number = 66, height: number = 40, label: string = '子主题') {
    const newCell = addNode(width, height, label)
    graph.addEdge({
      source: { cell: cell.id },
      target: { cell: newCell.id },
      attrs: {
        line: {
          strokeWidth: 2,
          stroke: '#A2B1C3',
          sourceMarker: null,
          targetMarker: null,
        },
      },
    })
    return newCell
  }

  setTimeout(() => {
    addNode(80, 40, '中心主题')
    graph.centerContent()
    graph.cleanHistory
  }, 100);

  return graph
}


  // 自动布局
export function layout(graph: Graph) {
  const nodes = graph.getNodes().filter(node => node.isVisible())
  const edges = graph.getEdges().filter(edge => edge.isVisible())
  const g = new dagre.graphlib.Graph()
  g.setGraph({ rankdir: appStore.rankdir, nodesep: 10, ranksep: 20 })
  g.setDefaultEdgeLabel(() => ({}))
  nodes.forEach((node) => {
    g.setNode(node.id, node.size())
  })
  edges.forEach((edge) => {
    g.setEdge(edge.getSourceCellId(), edge.getTargetCellId())
  })
  dagre.layout(g)

  nodes.forEach((node) => {
    const pos = g.node(node.id)
    const size = node.size()
    node.position(pos.x - size.width / 2, pos.y - size.height / 2)
  })
  edges.forEach((edge) => {
    const point = g.edge(edge.getSourceCellId(), edge.getTargetCellId()).points[1]
    const source = g.node(edge.getSourceCellId())
    const target = g.node(edge.getTargetCellId())
    if (['LR', 'RL'].includes(appStore.rankdir)) {
      source.x = point.x
      target.x = point.x
    } else {
      source.y = point.y
      target.y = point.y
    }
    edge.setVertices([source, target])
  })
  graph.centerContent()
}
